package controllers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import models.User;
import play.Logger;
import play.cache.Cache;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Http.Request;
import play.mvc.Result;
import play.mvc.Security;
import utils.IndexJob;
import utils.Key;
import utils.Operation;
import views.html.index;
import views.html.login;
import apis.IDOL;
import apis.IDOL.AddToTextIndexResponse;
import apis.IDOLApi;
import apis.SmartsheetApi;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.smartsheet.api.Smartsheet;
import com.smartsheet.api.SmartsheetException;
import com.smartsheet.api.models.Row;
import com.smartsheet.api.models.Sheet;

public class Application extends Controller {
	
	// display Dashboard
	@Security.Authenticated(Secured.class)
    public static Result index() {
    	
    	User loginUser = getLoginUser(request());
    	
    	// get sheet list
		List<Sheet> sheets = new ArrayList<Sheet>();
		try {
			Smartsheet smartsheet = SmartsheetApi.getSmartsheet(loginUser);
			
			// get the sheet list from cache
			sheets = (List<Sheet>) Cache.get(Key.getCacheKey(request(), Key.SHEETS));
			// get sheet list
			if (sheets == null) {
				sheets = SmartsheetApi.getSheets(smartsheet);
		    	if (sheets == null || sheets.isEmpty()) {
		    		setFlash("info", "There is no sheet, create some");
		    	} else {
		    		Cache.set(Key.getCacheKey(request(), Key.SHEETS), sheets, Key.CACHE_EXPIRE_30MIN);
		    	}
			}
		} catch(Exception e) {
			// display error message
			Logger.error("exception on listSheets", e);
			setFlash("warning", "Error on getting the sheet list, please try again");
		}
		
		// get IDOL indexes
		List<IDOL.Index> indexes = new ArrayList<IDOL.Index>();
		try {
			IDOL.ListIndexesResponse resp = IDOLApi.listIndexes();
			indexes = resp.index;
		} catch (Exception e) {
			Logger.error("exception on IDOL listIndexes", e);
			setFlash("warning", "Error on getting index list, please try again");
		}

		List<Operation> operations = Arrays.asList(Operation.values());
        return ok(index.render(loginUser, sheets, indexes, operations));
    }
	
	@Security.Authenticated(Secured.class)
    public static Result process(Long sheetId, String index, String operation, String columns) {
		Logger.info(sheetId+", "+index+", "+operation);
		Logger.info("columns: "+columns);
		

		Operation op = Operation.valueOf(operation);
		
		IndexJob job = new IndexJob();
		job.index = index;
		job.operation = op;
		job.columns = columns;
		
		User loginUser = Application.getLoginUser(request());
		
		try {
			Smartsheet smartsheet = SmartsheetApi.getSmartsheet(loginUser);
			Sheet sheet = getSheetFromCacheOrSmartsheet(smartsheet, sheetId);
			job.sheet = sheet;
			
			// handle operation
			if (op == Operation.ADD_TO_INDEX) {
				// add row data to index
				processAddToTextIndex(job);
			} else if (op == Operation.FIND_SIMILAR) {
				
			} else if (op == Operation.FIND_RELATED_CONCEPTS) {
			
			} else if (op == Operation.QUERY_TEXT_INDEX) {
				
			} else if (op == Operation.LANGUAGE_IDENTIFICATION) {
				
			} else if (op == Operation.SENTIMENT_ANALYSIS) {
				
			} else {
				Logger.warn("Unknown operation: "+op);
			}
			// save job to session
			
		} catch (Exception e) {
			setFlash("warning", "Error on processing sheet data");
		}
		return ok(operation.render(loginUser, job));
	}
	
	private static void processAddToTextIndex(IndexJob job) {
		// add row data to index
		for (Row row : job.sheet.getRows()) {
			IDOL.DocumentInput documentInput = new IDOL.DocumentInput();
			// change it to string type
			// add sync/async parameter
			AddToTextIndexResponse resp = IDOLApi.addToTextIndex(job.index, IDOL.InputSource.json, 
					documentInput, IDOL.DuplicateMode.replace);
		}
	}
	
	private static void processFindSimilar(IndexJob job) {
		// add row data to index
		for (Row row : job.sheet.getRows()) {
			IDOL.DocumentInput documentInput = new IDOL.DocumentInput();
			// first column is search text, rest of columns become fieldText
			List<IDOL.DocumentOutput> resp = IDOLApi.findSimilar(job.index, text, IDOL.Print.all, fieldText); 
		}
	}
	
	private static void processFindRelatedConcepts(IndexJob job) {
		// add row data to index
		for (Row row : job.sheet.getRows()) {
			IDOL.DocumentInput documentInput = new IDOL.DocumentInput();
			// first column is search text, rest of columns become fieldText
			List<IDOL.Entities> resp = IDOLApi.findRelatedConcepts(job.index, text, fieldText);
		}
	}

	/**
	 * Handle AJAX request to get the sheet data
	 * 
	 * @param sheetId the sheet id to fetch
	 * @return sheet in JSON format
	 */
	@Security.Authenticated(Secured.class)
	public static Result getSheet(Long sheetId) {
		User loginUser = Application.getLoginUser(request());
		
//		Logger.info("Selected sheet: "+sheetId);
		ObjectNode jsonResult = Json.newObject();
		try {
			Smartsheet smartsheet = SmartsheetApi.getSmartsheet(loginUser);
			Sheet selectedSheet = getSheetFromCacheOrSmartsheet(smartsheet, sheetId);

			JsonNode sheetNode = Json.toJson(selectedSheet);
			jsonResult.put("sheet", sheetNode);
//			Logger.info("sheet json: "+jsonResult.toString());
			return ok(jsonResult);
		} catch(Exception e) {
			Logger.error("Exception on smartsheet", e);
		}
		
		jsonResult.putNull("sheet");
		return ok(jsonResult);
	}
	
    /**
     * Login page.
     */
    public static Result login() {
    	User user = getLoginUser(request());
        return ok(login.render(user));
    }

    /**
     * Logout and clean the session.
     */
    public static Result logout() {
        session().clear();
        setFlash("success", "You've been signed out");
        return redirect(routes.Application.login());
    }

    /**
     * Get the currently logged in user.
     * 
     * @param request
     * @return
     */
    public static User getLoginUser(Request request) {
    	String username = request.username();
    	User user = User.findByEmail(username);
    	return user;
    }
 
    /**
     * Add flash message.
     * 
     * @param alert the	Bootstrap CSS alert type like success, info, warning or danger
     * @param msg the message displayed in the flash message box
     */
    public static void setFlash(String alert, String msg) {
    	flash("alert", alert);
    	flash("msg", msg);
    }
    
    /**
     * Clear session and cache once an attachment is sent
     */
    public static void clearSessionAndCache() {
		session().remove(Key.SHEET_ID);
		session().remove(Key.ROW_ID);
		session().remove(Key.ATTACHMENT_ID);
		
		String userId = session(Key.USER_ID);
        if (userId != null) {
	        User user = User.getById(Long.parseLong(userId));
	        Cache.remove(Key.getCacheKey(user, Key.SHEETS));
        }
		
    }
    
    public static Sheet getSheetFromCacheOrSmartsheet(Smartsheet smartsheet, Long sheetId) throws SmartsheetException {
		Sheet sheet = (Sheet) Cache.get(Key.getCacheKey(request(), sheetId.toString()));
		if (sheet == null) {
			sheet = SmartsheetApi.getSheet(smartsheet, sheetId);
			Cache.set(Key.getCacheKey(request(), sheetId.toString()), sheet, Key.CACHE_EXPIRE_30MIN);
		} else {
			Logger.info("get from cache");
		}
		return sheet;
    }
}
